import { DirectiveBinding } from 'vue';
import { checkRouteViewDepath, getOffsetParent, setDataSet } from '../utils/tools';
import { FocusBinding } from './focus';
import Pools from './pools';
import Views from './views';
import Service from '../utils/service';

/**
 * 焦点、区域构造类
 */
export default class Creater {
  readonly id: string;
  readonly name: string;
  readonly elem: HTMLElement;
  readonly sign: string = '';
  readonly group: string = '';
  readonly popup: string = '';
  static width: number;
  static height: number;
  static left: number;
  static top: number;
  static posAndSize: DOMRect;
  readonly assign: boolean = false;
  readonly appoints: boolean = false;
  readonly routeDepath: number;
  readonly routerEl: HTMLElement;
  readonly routeVpath: string;
  readonly routeViewName: string = "default";
  protected __service?: Service;
  __group__?: Creater;
  __list__?: Creater[];
  __sign__?: Creater[];
  __pools__?: Pools;
  __views__?: Views;
  data: any;
  selected: boolean = false;
  blur?: (pointer?: Creater) => void;
  focus?: (pointer?: Creater) => void;
  mouseover?: (event?: Event) => void;
  click?: (event?: Event) => void;
  constructor(name: string, elem: HTMLElement, binding: FocusBinding, service: Service) {
    this.name = name;
    this.elem = elem;
    this.__service = service
    elem._$FocusCreater = this;
    let { value, modifiers } = binding;
    if (modifiers && Object.keys(modifiers).length) {
      let { assign, appoints } = modifiers;
      this.assign = !!assign;
      this.appoints = !!appoints;
      let { def, sign, group, popup, blur, focus, mouseover, click } = value;
      this.data = def;
      this.sign = sign;
      this.group = group;
      this.popup = popup;
      this.blur = blur;
      this.focus = focus;
      this.mouseover = mouseover;
      this.click = click;
    } else {
      this.data = value;
    }
    // 构建焦点
    let { id, routeDepath, routerEl, routeVpath, routeViewName } = this.createDataSet(elem, name);
    this.id = id;
    this.routeDepath = routeDepath;
    this.routerEl = routerEl;
    this.routeVpath = routeVpath;
    this.routeViewName = routeViewName
  }

  // 元素X方向位置
  get left() {
    return getOffsetParent(this.elem, 'left');
  }

  // 元素Y方向位置
  get top() {
    return getOffsetParent(this.elem, 'top');
  }

  // 元素宽度
  get width() {
    return this.elem.offsetWidth;
  }

  // 元素高度
  get height() {
    return this.elem.offsetHeight;
  }

  /**
   * 获取元素相对视口的位置/尺寸信息
   */
  get posAndSize() {
    return this.elem.getBoundingClientRect();
  }

  /**
   * 获取元素dataset内容
   * @param {HTMLElement|Element} elem html元素节点
   * @param {Object} binding 自定义指令绑定的对象
   * @param {Object} context 虚拟节点中的context
   * @returns Object
   */
  createDataSet(elem: HTMLElement, name: string) {
    let id = name + '-' + (Math.random() + Date.now()).toString(36).replace(/\./, '');
    setDataSet(elem, id);
    let { routeDepath, routeVpath, routerEl, routeViewName } = checkRouteViewDepath(elem);
    return { id, routeDepath, routeVpath, routerEl, routeViewName };
  }

  /**
   * 更新焦点
   * @param {HTMLElement|Element} elem 元素节点
   * @param {Object} binding 自定义指令绑定的对象
   * @param {Vnode} vnode 虚拟节点
   */
  update(binding: DirectiveBinding) {
    let { value, modifiers } = binding;
    if (modifiers && Object.keys(modifiers).length) {
      let { def, blur, focus, mouseover, click } = value;
      this.data = def;
      this.blur = blur;
      this.focus = focus;
      this.mouseover = mouseover;
      this.click = click;
    } else {
      this.data = value;
    }
    this.updated();
  }

  /**
   * 兼容动态类名显示异常
   * @param {String} str 焦点/选中类名
   */
  add(str: string) {
    !this.elem._$FocusClass && (this.elem._$FocusClass = new Set());
    this.elem._$FocusClass.add(str);
    this.elem.classList.add(str);
  }

  /**
   * 兼容动态类名显示异常
   * @param {String} str 焦点/选中类名
   */
  updated() {
    if (this.elem._$FocusClass) {
      this.elem._$FocusClass.size &&
        [...this.elem._$FocusClass].forEach((item) => {
          this.elem.classList.add(item);
        });
    }
  }

  /**
   * 兼容动态类名显示异常
   * @param {String} str 焦点/选中类名
   */
  remove(str: string) {
    this.elem._$FocusClass?.delete(str);
    this.elem.classList.contains(str) && this.elem.classList.remove(str);
  }
}
